package fr.inserm.u915.tabixserver;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Pattern;
//import java.util.regex.Pattern;
import java.awt.Rectangle;

import java.io.IOException;


import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;


import net.sf.samtools.tabix.TabixReader;

import org.w3c.dom.Document;
import org.w3c.dom.Element;



/**
 * SVGBuilder
 * @author pierre
 *
 */
public class SVGBuilder
        {
        private static final Logger LOG=Logger.getLogger("tabix");
        private static final float FONT_TO_PIXEL_RATIO=0.6f;//empiric value
        private static final int DEFAULT_PANE_WIDTH=800;
        private static final int MARGIN_LEFT=200;
        private static final int MARGIN_TOP=200;
        private static final int FEATURE_HEIGHT=20;
        private static final int ENTITY_HEIGHT=12;
        private static final int LABEL_FONT_SIZE=(int)(FEATURE_HEIGHT*0.8);
        //where should we write a label ?

        
        //Regex finding URL
        //private final Pattern RS_PATTERN=Pattern.compile("rs[1-9][0-9]*");
        //private final Pattern ACN_PATTERN=Pattern.compile("(NM|NP)_[0-9]+");
        //private final Pattern ACN_PATTERN2=Pattern.compile("[A-Z][0-9A-Z]{5,7}(\\.[0-9]+)?");
        
        private DocumentBuilder docBuilder;
        private Build build;
        private Document dom;
        private Element svgRoot=null;
        //private Element svgStyle=null;
        private Element svgDefs=null;
        private Element svgScript=null;
        private Element drawing;
        //private Build organism;
        private Set<String> instancesIds=new HashSet<String>();
        private String chromosome;
        private int chrom_start=0;
        private int chrom_length=0;
        //private Integer resolution=null;
        private int pane_width=DEFAULT_PANE_WIDTH;
        private int maximum_count_mapped=10000;
        private int total_count=0;
        

		private class MappedXY extends MappedObject
			{
			static final int LABEL_IGNORED=0;
			static final int LABEL_ON_LEFT=1;
			static final int LABEL_ON_RIGHT=2;
			static final int LABEL_ON_MID=3;
			Element root=null;
			/** bounding box with label */
			Rectangle rectangle=new Rectangle();
			int label=0;
			MappedXY(Instance i,String tokens[])
				{
				super(i,tokens);
				}
			
			
			
			void paintGene(int y)
			 	{
                 Map<String,String> map= this.getMap();
                 if(map==null) return;
                 
                 y+=this.rectangle.y;
                 
                 boolean m_rna=false;
                 
                 //starts
                 String oStarts=map.get("exonStarts"); 
                 if(oStarts==null)
                         {
                         oStarts=map.get("tStarts"); 
                         if(oStarts!=null) m_rna=true;
                         }
                 
                 if(oStarts==null || oStarts.isEmpty()) return;
                 
                 
                 List<?> tokens=List.class.cast(oStarts);
                 int starts[]=new int[tokens.size()];
                 for(int i=0;i< tokens.size();++i) starts[i]=Integer.class.cast(tokens.get(i));
                 
                 //ends
                 Object oEnds=map.get(m_rna?"blockSizes":"exonEnds"); 
                 if(oEnds==null || !(oEnds instanceof List<?>)) return;
                 tokens= List.class.cast(oEnds);
                 int ends[]=new int[tokens.size()];
                 for(int i=0;i< tokens.size();++i)
                         {
                         ends[i]=Integer.class.cast(tokens.get(i));
                         }
                 if(starts.length!=ends.length) return;
                 if(m_rna)
                         {
                         for(int i=0;i< tokens.size();++i)
                                 {
                                 ends[i]+=starts[i];
                                 }
                         }
                 
                 
                 //
                 
                 final int exon_count= starts.length;
                 
                 List<Rectangle> exons= new ArrayList<Rectangle>(exon_count);
                 for(int i=0;i< exon_count;++i)
                         {
                         if(starts[i]>ends[i]) return;
                         if(ends[i]< SVGBuilder.this.chrom_start) continue;
                         if(starts[i]>= (SVGBuilder.this.chrom_start+SVGBuilder.this.chrom_length)) continue;
                         int pos1= base2pixel(starts[i]);
                         if(pos1<0) pos1=0;
                         int pos2= base2pixel(ends[i]);
                         if(pos2> getPaneWidth()) pos2=getPaneWidth();
                         if(pos1==pos2) ++pos2; 
                         Rectangle exon= new Rectangle(
                                 pos1,y,(pos2-pos1),this.rectangle.height
                                 );
                         if(!exons.isEmpty())
                                 {
                                 Rectangle last= exons.get(exons.size()-1);
                                 if(last.x+last.width>=exon.x)
                                         {
                                         last.width=(exon.x+exon.width)-last.x;
                                         }
                                 else
                                         {
                                         exons.add(exon);
                                         }
                                 }
                         else
                                 {
                                 exons.add(exon);
                                 }
                         }
                 //if(exons.isEmpty()) return null; non, faut tracer la ligne
                 
                 Element g= dom.createElement("g");
                 //transcription Line
                 int x1= base2pixel(this.getStart());
                 if(x1<0) x1=0;
                 int x2= base2pixel(this.getEnd());
                 if(x2>=getPaneWidth()) x2=getPaneWidth();
                 Element line= dom.createElement("line");
                 g.appendChild(line);
                 line.setAttribute("x1",String.valueOf(x1));
                 line.setAttribute("x2",String.valueOf(x2));
                 line.setAttribute("y1",String.valueOf(y+this.rectangle.height/2));
                 line.setAttribute("y2",String.valueOf(y+this.rectangle.height/2));
                 line.setAttribute("style","stroke:red;stroke-width:2px;");
                 
                 for(int i=0;i< exons.size();++i)
                         {
                         final int margin=5;
                         Rectangle exon= exons.get(i);
                         Element rect=null;
                         if(i==0 && getStrand()==Strand.MINUS && exon.width>=margin)
                                 {
                                 rect= dom.createElement("polygon");
                                 rect.setAttribute("points",
                                                 ""+
                                                 (exon.x+margin)+","+y+" "+
                                                 (exon.x+exon.width)+","+y+" "+
                                                 (exon.x+exon.width)+","+(y+this.rectangle.height)+" "+
                                                 (exon.x+margin)+","+(y+this.rectangle.height)+" "+
                                                 (exon.x)+","+(y+this.rectangle.height/2)
                                                 );
                                 }
                         else if(i==exons.size()-1 && getStrand()==Strand.PLUS && exon.width>=margin)
                                 {
                                 rect= dom.createElement("polygon");
                                 rect.setAttribute("points",
                                         ""+
                                         (exon.x+exon.width-margin)+","+y+" "+
                                         (exon.x)+","+y+" "+
                                         (exon.x)+","+(y+this.rectangle.height)+" "+
                                         (exon.x+exon.width-margin)+","+(y+this.rectangle.height)+" "+
                                         (exon.x+exon.width)+","+(y+this.rectangle.height/2)
                                         );
                                 }
                         else
                                 {
                                 rect= dom.createElement("rect");
                                 rect.setAttribute("x",String.valueOf(exon.x));
                                 rect.setAttribute("y",String.valueOf(exon.y));
                                 rect.setAttribute("width",String.valueOf(exon.width));
                                 rect.setAttribute("height",String.valueOf(exon.height));
                                 }
                         
                         g.appendChild(rect);
                         rect.setAttribute("style","stroke:black;fill:yellow;");
                         }
			 	}
			
			}
        
		/**
		 * 
		 * InstancePane
		 *
		 */
        private class InstancePane
        	{
        	Element root;
        	Instance instance;
        	List<MappedXY> objects=new ArrayList<MappedXY>();
        	int track_height=0;
        	private int min_distance=2;

        	public InstancePane(Instance instance)
        		{
        		this.instance=instance;
        		}
        	
        	private boolean overlap(final Rectangle o1,final Rectangle o2)
	            {
	            if(o1.x>o2.x)
	                    {
	                    return overlap(o2, o1);
	                    }
	            
	            int R1= o1.x+o1.width;
	            int L2= o2.x;
	            return (R1+ min_distance >= L2);
	            }

        	
        	void run() throws IOException
        		{
        		List<List<MappedXY>> lines= new ArrayList<List<MappedXY>>();
        		
        		Pattern pattern=Pattern.compile(instance.getTable().getPattern());
                TabixReader r=new TabixReader(instance.getPath());
                Iterator<String> iter=r.query(
                		instance.getTable().getChromosomeNaming().normalize(SVGBuilder.this.chromosome),
                		SVGBuilder.this.chrom_start,
                		SVGBuilder.this.chrom_start+SVGBuilder.this.chrom_length
                		);
                while(iter.hasNext() && SVGBuilder.this.total_count< SVGBuilder.this.maximum_count_mapped)
                	{
                	String s=iter.next();
                	String tokens[]=pattern.split(s);
                	
                	MappedXY inserted=new MappedXY(instance,tokens);
                    if(inserted.getEnd()< SVGBuilder.this.chrom_start) continue;
                    if(inserted.getStart()>= (SVGBuilder.this.chrom_start+SVGBuilder.this.chrom_length)) continue;

                    //get bounding box
                    int left_box;
                    int right_box;
                    int side;
                    
                    left_box= base2pixel(inserted.getStart());
                    if(left_box<0) left_box=0;
                    right_box= base2pixel(inserted.getEnd());
                    if(right_box>=getPaneWidth()) right_box=getPaneWidth();
                    float name_size= (inserted.getName().length()+2) * LABEL_FONT_SIZE * FONT_TO_PIXEL_RATIO;
                    if(name_size==0 )
                            {
                            side= MappedXY.LABEL_IGNORED;
                            }
                    else if(left_box==0 && right_box==getPaneWidth())
                            {
                            side= MappedXY.LABEL_ON_MID;
                            }
                    else if( (right_box-left_box) > name_size)
                            {
                            side= MappedXY.LABEL_ON_MID;
                            }
                    else if(name_size< left_box)
                            {
                            side= MappedXY.LABEL_ON_LEFT;
                            left_box-=name_size;
                            }
                    else if(getPaneWidth()- right_box > name_size)
                            {
                            side= MappedXY.LABEL_ON_RIGHT;
                            right_box+=name_size;
                            }
                    else
                            {
                            side= MappedXY.LABEL_IGNORED;
                            }
                   
                    inserted.label=side;
                    inserted.rectangle.x=left_box;
                    inserted.rectangle.width=right_box-left_box;	                    
                	this.objects.add(inserted);
                	
                	
                	inserted.rectangle.height= ENTITY_HEIGHT;
                    int y;
                    for(y=0;y<lines.size();++y)
                         {
                     	int x=0;
                         List<MappedXY> mappeds= lines.get(y);
                         for(x=0;x< mappeds.size();++x)
                                 {
                                 if(overlap(mappeds.get(x).rectangle,inserted.rectangle)) break;
                                 }
                         if(x==mappeds.size())
                                 {
                        	 	inserted.rectangle.y= y*ENTITY_HEIGHT;
                                 mappeds.add(inserted);
                                 break;
                                 }
                         }
                     if(y==lines.size())
                         {
                         List<MappedXY> line=new ArrayList<MappedXY>();
                         inserted.rectangle.y=lines.size()*ENTITY_HEIGHT;
                         line.add(inserted);
                         lines.add(line);
                         }
	                     
                	
                	++SVGBuilder.this.total_count;
                	}
                //close iterator
                r.close();
                
               /* paint */
	             
                  final int starting_y= 0;
	              int max_y=starting_y;
	              //final int histogram_height=100;
	              //if(scanner.max_histogram_count==0 && scanner.lines.isEmpty()) return null;
	              //if(scanner.ltHistogram.getMaximum()==0 && scanner._mappedXY.isEmpty()) return null;
	              
	              this.root = dom.createElementNS(SVG.NS,"g");
	              //g1.setAttribute("style","fill:url(#grad"+j+");stroke:black;");
	              this.root.setAttribute("style","fill:blue;stroke:black;");
	              this.root.setAttribute("title",instance.getLabel());
	              
	              
	              for(MappedXY o: this.objects)
	                      {
	            	  	  this.root.appendChild(visualizeObject(
	                                      instance,o,
	                                      starting_y
	                                      ));
	                              
	                       max_y= Math.max(
	                                      max_y,
	                                      starting_y+o.rectangle.y+o.rectangle.height+2
	                                      );
	                      }
	              
	              //draw horizontal ticks
	              /*if( scanner.ltHistogram.getMaximum()>0)
	                      {
	                      HistogramPainter painter=getHistogramPainter(track);
	                      Element histo2dom= painter.paint(this.dom, scanner.ltHistogram);
	                      if(histo2dom!=null)
	                              {
	                              histo2dom.setAttribute("transform", "translate(0,"+this.max_y+")");
	                              g1.appendChild(histo2dom);
	                              }
	                      
	                      max_y+=2+painter.getHeight();
	                      }*/
	              
	              this.track_height=Math.max(50,max_y-starting_y);
	              max_y=starting_y+this.track_height;
	              
	              /** create LEFT margin with label */
	              Element label= dom.createElementNS(SVG.NS,"g");
	              label.setAttribute("title", instance.getLabel());
	              label.setAttribute("transform", "translate(-"+MARGIN_LEFT+",0)");
	              this.root.appendChild(label);
	              
	              Element rect= dom.createElementNS(SVG.NS,"rect");
	              label.appendChild(rect);
	              rect.setAttribute("x", String.valueOf(0));
	              rect.setAttribute("y", String.valueOf(starting_y));
	              rect.setAttribute("width", String.valueOf(MARGIN_LEFT+1));
	              rect.setAttribute("height",String.valueOf(this.track_height));
	              rect.setAttribute("style", "fill:lightgray;stroke:black;stroke-width:2px;");
	              
	              Element tit= dom.createElementNS(SVG.NS,"text");
	              label.appendChild(tit);
	              tit.appendChild(dom.createTextNode(instance.getLabel()));
	              tit.setAttribute("x", String.valueOf(MARGIN_LEFT-5));
	              tit.setAttribute("y", String.valueOf(starting_y+(this.track_height)/2 +LABEL_FONT_SIZE/2-2));
	              tit.setAttribute("text-anchor","end"); 
	              }
        	}
        
        
        
        public SVGBuilder()
        	{
        	   try {
                   DocumentBuilderFactory f=DocumentBuilderFactory.newInstance();
                   f.setCoalescing(true);
                   f.setNamespaceAware(true);
                   f.setValidating(false);
                   f.setExpandEntityReferences(true);
                   f.setIgnoringComments(true);
                   f.setIgnoringElementContentWhitespace(false);
                   this.docBuilder= f.newDocumentBuilder();
        	   		}
        	   catch(Exception err)
        	   	{
        		throw new RuntimeException(err);   
        	   	}
        	   
        	}
        
        public void setBuild(Build build)
        	{
			this.build = build;
			}
        
        public void setSegment(Segment seg)
        	{
        	this.chromosome=seg.getChromosome();
        	this.chrom_start=seg.getStart();
        	this.chrom_length=Math.max(1,seg.getEnd()-this.chrom_start);
        	}
        
        public void setInstanceIds(Set<String> instancesId)
        	{
        	this.instancesIds=new HashSet<String>(instancesId);
        	}
        
        public Document makeDocument() throws IOException
                {
	
                this.dom=this.docBuilder.newDocument();
                
                this.svgRoot = this.dom.createElementNS(SVG.NS,"svg");
                this.dom.appendChild(this.svgRoot );
                this.svgRoot.setAttribute("xmlns", SVG.NS);
                this.svgRoot.setAttribute("xmlns:xlink", XLink.NS);
                this.svgRoot.setAttribute("style",
                        "font-size:"+LABEL_FONT_SIZE+"px;"+
                        "font-family:courier;"+
                        "font-weight:lighter;"+
                        "font-style:normal;"+
                        "stroke:black;fill:none;stroke-width:0.3px;"
                        );
                
                
                Element title= this.dom.createElementNS(SVG.NS,"title");
                title.appendChild(dom.createTextNode(chromosome+":"+(chrom_start)+"-"+(chrom_start+chrom_length)));
                this.svgRoot .appendChild(title);
                title= this.dom.createElementNS(SVG.NS,"desc");
                title.appendChild(dom.createTextNode("CNG/CEPH 2009. Created with "+getClass().getName()));
                this.svgRoot .appendChild(title);
                
                this.svgScript= this.dom.createElementNS(SVG.NS,"script");
                this.svgRoot .appendChild(this.svgScript);
                this.svgScript.setAttribute("type", "text/ecmascript");
                this.svgScript.appendChild(dom.createCDATASection("\n"));
                
                this.svgDefs= this.dom.createElementNS(SVG.NS,"defs");
                this.svgRoot .appendChild(this.svgDefs);
                Element grad= this.dom.createElementNS(SVG.NS,"linearGradient");
                this.svgDefs.appendChild(grad);
                grad.setAttribute("id", "background");
                grad.setAttribute("x1", "50%");
                grad.setAttribute("y1", "0%");
                grad.setAttribute("x2", "50%");
                grad.setAttribute("y2", "100%");
                Element stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "0%");
                stop.setAttribute("stop-color","lightgray");
                stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "100%");
                stop.setAttribute("stop-color","gray");
                
                grad= this.dom.createElementNS(SVG.NS,"linearGradient");
                this.svgDefs.appendChild(grad);
                grad.setAttribute("id", "hgrad");
                grad.setAttribute("x1", "50%");
                grad.setAttribute("y1", "0%");
                grad.setAttribute("x2", "50%");
                grad.setAttribute("y2", "100%");
                stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "5%");
                stop.setAttribute("stop-color","black");
                stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "50%");
                stop.setAttribute("stop-color","lavender");
                stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "85%");
                stop.setAttribute("stop-color","black");
                
                
                grad= this.dom.createElementNS(SVG.NS,"linearGradient");
                this.svgDefs.appendChild(grad);
                grad.setAttribute("id", "vgrad");
                grad.setAttribute("x1", "5%");
                grad.setAttribute("y1", "50%");
                grad.setAttribute("x2", "95%");
                grad.setAttribute("y2", "50%");
                stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "5%");
                stop.setAttribute("stop-color","black");
                stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "50%");
                stop.setAttribute("stop-color","green");
                stop= this.dom.createElementNS(SVG.NS,"stop");
                grad.appendChild(stop);
                stop.setAttribute("offset", "85%");
                stop.setAttribute("stop-color","black");
                
                
                //the drawing itslef
                this.drawing= dom.createElementNS(SVG.NS,"g");
                this.drawing.setAttribute("transform", "translate("+MARGIN_LEFT+",0)");
                this.svgRoot.appendChild(drawing);
        
                int total_count=0;
                int top_y=MARGIN_TOP;
                
                 //loop over each instances
                for(Instance instance:this.build.getAllInstances())
	                {
                	if(total_count>= this.maximum_count_mapped) break;
                	if(!this.instancesIds.contains(instance.getId())) continue;
                	InstancePane trackPane=new InstancePane(instance);
                	
	                trackPane.run();
	                trackPane.root.setAttribute("transform", "translate(0,"+top_y+")");
	                top_y+=trackPane.track_height;
	                this.drawing.appendChild(trackPane.root);
	                }
                
               
              
        
        
                
                this.svgRoot.setAttribute("width",String.valueOf(getPaneWidth()+MARGIN_LEFT));
                this.svgRoot.setAttribute("height",String.valueOf(top_y));
                
                
                
                final int num_steps=10;
                int step=(int)(Math.pow(10,Math.ceil(Math.log10(chrom_length)))/num_steps);
                if(step>=10 && step*2>=chrom_length)
                        {
                        step/=10;
                        }
                
                if(step>0)
                        {
                        //create a scale with vertical bars
                        Element gscale= dom.createElementNS(SVG.NS, "g");
                        drawing.insertBefore( gscale,drawing.getFirstChild());
                        gscale.setAttribute("style", "stroke:none;");
                        int ticks = chrom_start - chrom_start%step;
                        
                        while(ticks<= chrom_start+chrom_length)
                                {
                                float x= (float)base2pixel(ticks);
                                if(x>=0 && x<getPaneWidth())
                                        {
                                        Element line= dom.createElementNS(SVG.NS, "rect");
                                        line.setAttribute("style","fill:white;");
                                        line.setAttribute("x", String.valueOf(x));
                                        line.setAttribute("y", "0");
                                        line.setAttribute("width", "2");
                                        line.setAttribute("height", String.valueOf(top_y));
                                        gscale.appendChild(line);
                                        line= dom.createElementNS(SVG.NS, "rect");
                                        line.setAttribute("style","fill:gray;");
                                        line.setAttribute("x", String.valueOf(x));
                                        line.setAttribute("y", "0");
                                        line.setAttribute("width", "1");
                                        line.setAttribute("height", String.valueOf(top_y));
                                        gscale.appendChild(line);
                                        
                                        Element t=  dom.createElementNS(SVG.NS, "text");
                                        t.appendChild(dom.createTextNode(niceNumber(ticks)));
                                        t.setAttribute("style", "stroke:black;font-size:9pt;");
                                        t.setAttribute("x", "0");
                                        t.setAttribute("y", "0");
                                        t.setAttribute("transform", "translate("+(x+2)+",10) rotate(90)");
                                        gscale.appendChild(t);
                                        }
                                
                                if(step>=10)
                                        {
                                        for(int t2=ticks;t2<ticks+step;t2+=step/10)
                                                {
                                                float x2= (float)(((t2-chrom_start)/(double)chrom_length)*getPaneWidth());
                                                if(!(x2>=0 && x2<getPaneWidth())) continue;
                                                Element line2= dom.createElementNS(SVG.NS, "line");
                                                line2.setAttribute("style","stroke:gray;");
                                                line2.setAttribute("x1", String.valueOf(x2));
                                                line2.setAttribute("y1", "0");
                                                line2.setAttribute("x2", String.valueOf(x2));
                                                line2.setAttribute("y2", String.valueOf(top_y));
                                                gscale.appendChild(line2);
                                                }
                                        }
                                
                                ticks+=step;
                                }
                        }
                //a background for the drawing
                Element back= dom.createElementNS(SVG.NS,"rect");
                this.drawing.insertBefore(back,this.drawing.getFirstChild());
                back.setAttribute("x", "0");
                back.setAttribute("y", "0");
                back.setAttribute("width", String.valueOf(getPaneWidth()));
                back.setAttribute("height",String.valueOf(top_y));
                back.setAttribute("style","fill:url(#background);stroke:black;");
                

                Document doc=this.dom;
                this.dom=null;
                return doc;
                }
        
      
        
        public void setPaneWidth(int paneWidth)
                {
                pane_width = paneWidth;
                }
        
      private int getPaneWidth()
                {
                return pane_width;
                }
        

        
        
       
        
        protected Element visualizeObject(
                final Instance track,
                final MappedXY o,
                final int y
                )
                {
                Element rect= o.root;
                Rectangle bounds= o.rectangle;

                
                if(rect==null) rect=dom.createElementNS(SVG.NS, "rect");
                Element to_be_returned=rect;
                int pix_start=base2pixel(o.getStart());
                if(pix_start<0) pix_start=0;
                int pix_end= base2pixel(o.getEnd());
                if(pix_end>=getPaneWidth()) pix_end=getPaneWidth();

                rect.setAttribute("x", String.valueOf(pix_start));
                rect.setAttribute("y", String.valueOf(y+bounds.y));
                rect.setAttribute("width", String.valueOf(Math.max(1,pix_end-pix_start)));
                rect.setAttribute("height",String.valueOf(bounds.height));
                rect.setAttribute("style","fill:url(#hgrad);stroke:black;");
                
                Element g= null;
                Element text= null;
                final int text_y= bounds.y+y+bounds.height-(bounds.height- LABEL_FONT_SIZE)/2 -2;
                switch(o.label)
                        {
                        case MappedXY.LABEL_IGNORED:break;
                        case MappedXY.LABEL_ON_LEFT:
                                {
                                text= dom.createElementNS(SVG.NS, "text");
                                g= dom.createElementNS(SVG.NS, "g");
                                g.appendChild(text);
                                text.appendChild(dom.createTextNode(o.getName()));
                                text.setAttribute("x",String.valueOf(pix_start-1));
                                text.setAttribute("y",String.valueOf(text_y));
                                text.setAttribute("text-anchor","end");
                                g.appendChild(rect);
                                break;
                                }
                        case MappedXY.LABEL_ON_RIGHT:
                                {
                                text= dom.createElementNS(SVG.NS, "text");
                                g= dom.createElementNS(SVG.NS, "g");
                                g.appendChild(text);
                                text.appendChild(dom.createTextNode(o.getName()));
                                text.setAttribute("x",String.valueOf(pix_end+1));
                                text.setAttribute("y",String.valueOf(text_y));
                                text.setAttribute("text-anchor","start");
                                g.appendChild(rect);
                                break;
                                }
                        case MappedXY.LABEL_ON_MID:
                                {
                                text= dom.createElementNS(SVG.NS, "text");
                                g= dom.createElementNS(SVG.NS, "g");
                                g.appendChild(rect);
                                
                                g.appendChild(text);
                                text.appendChild(dom.createTextNode(o.getName()));
                                text.setAttribute("x",String.valueOf((pix_end+pix_start)/2));
                                text.setAttribute("y",String.valueOf(text_y));
                                text.setAttribute("text-anchor","middle");
                                break;
                                }
                        }
                
                if(g!=null)
                        {
                        to_be_returned=g;
                        }
                
                
                String url= o.getURL();
                if(url!=null)
                        {
                        Element anchor=dom.createElementNS(SVG.NS, "a");
                        anchor.setAttributeNS(XLink.NS,"xlink:href",url);
                        anchor.appendChild(to_be_returned);
                        to_be_returned=anchor;
                        }
                to_be_returned.setAttribute("title",o.getName());
                //to_be_returned.setAttribute("id",track.getName()+":"+o.getObject().getId());
                return to_be_returned;
                }
      
        
      
        
        
        
        private int base2pixel(final int genome_pos)
                {
                return (int)(((genome_pos- this.chrom_start)/(double)this.chrom_length)*getPaneWidth());
                }

        
        
        private String niceNumber(final int i)
                {
                String s=String.valueOf(i);
                StringBuilder b= new StringBuilder(s.length());
                for(int j=0;j< s.length();j++)
                        {
                        if(j!=0 && j%3==0) b.insert(0, ' ');
                        b.insert(0,s.charAt(s.length()-1-j));
                        }
                return b.toString();
                }
        
        }